import 'dart:async';
import 'dart:typed_data';

import 'package:flutter_test/flutter_test.dart';
import 'package:ble_ota_plugin/src/ota_upgrade_manager.dart';
import 'package:ble_ota_plugin/src/ota_upgrade_status.dart';
import 'package:ble_ota_plugin/src/user_action_type.dart';
import 'package:http/http.dart' as http;

void main() {
  test('full transfer and upgrade flow with initial firmware data', () async {
    // 准备一个小固件数据（1000字节）
    final firmware =
        Uint8List.fromList(List<int>.generate(1000, (i) => i % 256));

    final statuses = <OtaUpgradeStatus>[];
    final progresses = <double>[];
    final userActions = <UserActionType>[];

  late final OtaUpgradeManager manager;
  manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      initialFirmwareData: firmware,
      sendData: (Uint8List bytes) async {
        // 对所有包和验证包返回成功
        return true;
      },
      onProgress: (double progress, int position) {
        progresses.add(progress);
      },
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {
        userActions.add(action);
      },
      // 加速升级模拟，避免长时间等待
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    // 启动升级，会跳过实际网络下载并进行传输，然后进入等待用户操作阶段
    await manager.startUpgrade();

    // 断言已经完成下载与传输，且处于等待用户操作
    expect(statuses, contains(OtaUpgradeStatus.downloadSuccess));
    expect(statuses, contains(OtaUpgradeStatus.transferSuccess));
    expect(statuses, contains(OtaUpgradeStatus.waitingUserAction));
    expect(userActions, contains(UserActionType.restartDevice));

    // 模拟用户选择重启设备并等待升级完成
    await manager.onUserActionCompleted(UserActionType.restartDevice);

    // 最终应该为升级成功（因为 sendData 总是返回 true）
    expect(statuses.last, equals(OtaUpgradeStatus.upgradeSuccess));

    manager.dispose();
  });

  test('pause and resume transfer', () async {
    final firmware = Uint8List.fromList(List<int>.generate(2000, (i) => i % 256));

    final statuses = <OtaUpgradeStatus>[];

  late final OtaUpgradeManager manager;
  manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      initialFirmwareData: firmware,
      sendData: (Uint8List bytes) async {
        // 快速返回
        return true;
      },
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
        // 当进入 transferring 时，立即暂停以测试暂停逻辑
        if (status == OtaUpgradeStatus.transferring) {
          manager.pauseTransfer();
        }
      },
      onUserActionRequired: (UserActionType action) {},
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    final startFuture = manager.startUpgrade();

    // 等待 transferPaused 状态
    final paused = await _waitForStatus(statuses, OtaUpgradeStatus.transferPaused,
        timeout: const Duration(seconds: 2));
    expect(paused, isTrue, reason: 'transfer did not pause in time');

    // 恢复传输
    manager.resumeTransfer();

    await startFuture;

    expect(statuses, contains(OtaUpgradeStatus.transferPaused));
    expect(statuses, contains(OtaUpgradeStatus.transferSuccess));

    manager.dispose();
  });

  test('http download streams chunks successfully', () async {
    // 模拟 http client 返回多个 chunk 的流式响应
    final chunks = [List<int>.filled(400, 1), List<int>.filled(300, 2), List<int>.filled(300, 3)];
    final client = _FakeClient((http.BaseRequest request) async {
      final stream = Stream<List<int>>.fromIterable(chunks);
      return http.StreamedResponse(stream, 200, contentLength: 1000);
    });

    final statuses = <OtaUpgradeStatus>[];

    final manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      httpClient: client,
      sendData: (Uint8List bytes) async => true,
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {},
      onTotalSize: (int total) {},
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    await manager.startUpgrade();

    expect(statuses, contains(OtaUpgradeStatus.downloadSuccess));
    expect(statuses, contains(OtaUpgradeStatus.transferSuccess));

    manager.dispose();
  });

  test('http download failure (non-200) sets downloadFailed', () async {
    final client = _FakeClient((http.BaseRequest request) async {
      return http.StreamedResponse(Stream<List<int>>.empty(), 404);
    });

    final statuses = <OtaUpgradeStatus>[];

    final manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      httpClient: client,
      sendData: (Uint8List bytes) async => true,
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {},
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    await manager.startUpgrade();

    expect(statuses, contains(OtaUpgradeStatus.downloadFailed));

    manager.dispose();
  });

  test('transfer failure triggers onUserActionRequired retry', () async {
    final firmware = Uint8List.fromList(List<int>.generate(1000, (i) => i % 256));

    final statuses = <OtaUpgradeStatus>[];
    final userActions = <UserActionType>[];

    final manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      initialFirmwareData: firmware,
      sendData: (Uint8List bytes) async {
        // 始终返回 false，触发 transferFailed
        return false;
      },
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {
        userActions.add(action);
      },
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    await manager.startUpgrade();

    expect(statuses, contains(OtaUpgradeStatus.transferFailed));
    expect(userActions, contains(UserActionType.retryTransfer));

    manager.dispose();
  });

  test('sendData retries then succeeds', () async {
    // 固件数据使得会有多个包（1000 字节，packetSize 默认 512）
    final firmware =
        Uint8List.fromList(List<int>.generate(1000, (i) => i % 256));

    final statuses = <OtaUpgradeStatus>[];
    int callCount = 0;

    final manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      initialFirmwareData: firmware,
      sendData: (Uint8List bytes) async {
        // 前两次调用返回 false，之后返回 true，验证重试逻辑
        callCount++;
        if (callCount <= 2) return false;
        return true;
      },
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {},
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    await manager.startUpgrade();

    // 最终应完成传输并进入等待用户操作
    expect(statuses, contains(OtaUpgradeStatus.transferSuccess));
    expect(statuses, contains(OtaUpgradeStatus.waitingUserAction));

    manager.dispose();
  });

  test('cancel during transfer stops the process and sets cancelled status',
      () async {
    // 使用较大固件以产生多次分包，便于在中途取消
    final firmware =
        Uint8List.fromList(List<int>.generate(5000, (i) => i % 256));

    final statuses = <OtaUpgradeStatus>[];

    // 控制第一个包的发送，让测试在发送过程中触发 cancel
    final firstPacketCompleter = Completer<void>();
    bool firstPacketBlocked = true;

    final manager = OtaUpgradeManager(
      firmwareUrl: 'http://example.test/firmware.bin',
      initialFirmwareData: firmware,
      sendData: (Uint8List bytes) async {
        if (firstPacketBlocked) {
          // 阻塞，直到测试决定放行
          await firstPacketCompleter.future;
          firstPacketBlocked = false;
          return true;
        }
        // 之后的包快速返回
        await Future.delayed(const Duration(milliseconds: 5));
        return true;
      },
      onProgress: (double progress, int position) {},
      onStatus: (OtaUpgradeStatus status) {
        statuses.add(status);
      },
      onUserActionRequired: (UserActionType action) {},
      // 加速升级模拟以缩短测试时间
      upgradeSimulationSteps: 2,
      upgradeStepDuration: const Duration(milliseconds: 1),
    );

    // 启动但不等待完成，以便在传输期间调用 cancel
    final startFuture = manager.startUpgrade();

    // 等待状态进入 transferring（带超时保护）
    final started = await _waitForStatus(
        statuses, OtaUpgradeStatus.transferring,
        timeout: const Duration(seconds: 2));
    expect(started, isTrue, reason: 'transfer did not start in time');

    // 此时第一个包还被阻塞，触发取消
    await manager.cancelUpgrade();

    // 放行第一个包，使内部流程可以完成清理
    if (!firstPacketCompleter.isCompleted) {
      firstPacketCompleter.complete();
    }

    // 等待 startFuture 完成
    await startFuture;

    // 状态应包含 cancelled
    expect(statuses, contains(OtaUpgradeStatus.cancelled));

    manager.dispose();
  });
}

// 简单的 Fake http client，用于测试注入 StreamedResponse
class _FakeClient extends http.BaseClient {
  final Future<http.StreamedResponse> Function(http.BaseRequest request) _handler;
  _FakeClient(this._handler);

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    return _handler(request);
  }
}

// 辅助：在列表中等待特定状态出现，超时则返回 false
Future<bool> _waitForStatus(
    List<OtaUpgradeStatus> statuses, OtaUpgradeStatus target,
    {Duration timeout = const Duration(seconds: 1)}) async {
  final end = DateTime.now().add(timeout);
  while (DateTime.now().isBefore(end)) {
    if (statuses.contains(target)) return true;
    await Future.delayed(const Duration(milliseconds: 10));
  }
  return false;
}
